1use crate::cmp;
2use crate::fmt::{self, Debug};
3use crate::iter::{FusedIterator, InPlaceIterable, SourceIter, TrustedFused, TrustedLen};
4use crate::num::NonZero;
5
6#[derive(Clone)]
11#[must_use = "iterators are lazy and do nothing unless consumed"]
12#[stable(feature = "rust1", since = "1.0.0")]
13pub struct Zip<A, B> {
14 a: A,
15 b: B,
16 index: usize,
18 len: usize,
19}
20impl<A: Iterator, B: Iterator> Zip<A, B> {
21 pub(in crate::iter) fn new(a: A, b: B) -> Zip<A, B> {
22 ZipImpl::new(a, b)
23 }
24 fn super_nth(&mut self, mut n: usize) -> Option<(A::Item, B::Item)> {
25 while let Some(x) = Iterator::next(self) {
26 if n == 0 {
27 return Some(x);
28 }
29 n -= 1;
30 }
31 None
32 }
33}
34
35#[stable(feature = "iter_zip", since = "1.59.0")]
65pub fn zip<A, B>(a: A, b: B) -> Zip<A::IntoIter, B::IntoIter>
66where
67 A: IntoIterator,
68 B: IntoIterator,
69{
70 ZipImpl::new(a.into_iter(), b.into_iter())
71}
72
73#[stable(feature = "rust1", since = "1.0.0")]
74impl<A, B> Iterator for Zip<A, B>
75where
76 A: Iterator,
77 B: Iterator,
78{
79 type Item = (A::Item, B::Item);
80
81 #[inline]
82 fn next(&mut self) -> Option<Self::Item> {
83 ZipImpl::next(self)
84 }
85
86 #[inline]
87 fn size_hint(&self) -> (usize, Option<usize>) {
88 ZipImpl::size_hint(self)
89 }
90
91 #[inline]
92 fn nth(&mut self, n: usize) -> Option<Self::Item> {
93 ZipImpl::nth(self, n)
94 }
95
96 #[inline]
97 fn fold<Acc, F>(self, init: Acc, f: F) -> Acc
98 where
99 F: FnMut(Acc, Self::Item) -> Acc,
100 {
101 ZipImpl::fold(self, init, f)
102 }
103
104 #[inline]
105 unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item
106 where
107 Self: TrustedRandomAccessNoCoerce,
108 {
109 unsafe { ZipImpl::get_unchecked(self, idx) }
112 }
113}
114
115#[stable(feature = "rust1", since = "1.0.0")]
116impl<A, B> DoubleEndedIterator for Zip<A, B>
117where
118 A: DoubleEndedIterator + ExactSizeIterator,
119 B: DoubleEndedIterator + ExactSizeIterator,
120{
121 #[inline]
122 fn next_back(&mut self) -> Option<(A::Item, B::Item)> {
123 ZipImpl::next_back(self)
124 }
125}
126
127#[doc(hidden)]
129trait ZipImpl<A, B> {
130 type Item;
131 fn new(a: A, b: B) -> Self;
132 fn next(&mut self) -> Option<Self::Item>;
133 fn size_hint(&self) -> (usize, Option<usize>);
134 fn nth(&mut self, n: usize) -> Option<Self::Item>;
135 fn next_back(&mut self) -> Option<Self::Item>
136 where
137 A: DoubleEndedIterator + ExactSizeIterator,
138 B: DoubleEndedIterator + ExactSizeIterator;
139 fn fold<Acc, F>(self, init: Acc, f: F) -> Acc
140 where
141 F: FnMut(Acc, Self::Item) -> Acc;
142 unsafe fn get_unchecked(&mut self, idx: usize) -> <Self as Iterator>::Item
144 where
145 Self: Iterator + TrustedRandomAccessNoCoerce;
146}
147
148macro_rules! zip_impl_general_defaults {
151 () => {
152 default fn new(a: A, b: B) -> Self {
153 Zip {
154 a,
155 b,
156 index: 0, len: 0, }
159 }
160
161 #[inline]
162 default fn next(&mut self) -> Option<(A::Item, B::Item)> {
163 let x = self.a.next()?;
164 let y = self.b.next()?;
165 Some((x, y))
166 }
167
168 #[inline]
169 default fn nth(&mut self, n: usize) -> Option<Self::Item> {
170 self.super_nth(n)
171 }
172
173 #[inline]
174 default fn next_back(&mut self) -> Option<(A::Item, B::Item)>
175 where
176 A: DoubleEndedIterator + ExactSizeIterator,
177 B: DoubleEndedIterator + ExactSizeIterator,
178 {
179 let a_sz = self.a.len();
184 let b_sz = self.b.len();
185 if a_sz != b_sz {
186 if a_sz > b_sz {
188 for _ in 0..a_sz - b_sz {
189 self.a.next_back();
190 }
191 } else {
192 for _ in 0..b_sz - a_sz {
193 self.b.next_back();
194 }
195 }
196 }
197 match (self.a.next_back(), self.b.next_back()) {
198 (Some(x), Some(y)) => Some((x, y)),
199 (None, None) => None,
200 _ => unreachable!(),
201 }
202 }
203 };
204}
205
206#[doc(hidden)]
208impl<A, B> ZipImpl<A, B> for Zip<A, B>
209where
210 A: Iterator,
211 B: Iterator,
212{
213 type Item = (A::Item, B::Item);
214
215 zip_impl_general_defaults! {}
216
217 #[inline]
218 default fn size_hint(&self) -> (usize, Option<usize>) {
219 let (a_lower, a_upper) = self.a.size_hint();
220 let (b_lower, b_upper) = self.b.size_hint();
221
222 let lower = cmp::min(a_lower, b_lower);
223
224 let upper = match (a_upper, b_upper) {
225 (Some(x), Some(y)) => Some(cmp::min(x, y)),
226 (Some(x), None) => Some(x),
227 (None, Some(y)) => Some(y),
228 (None, None) => None,
229 };
230
231 (lower, upper)
232 }
233
234 default unsafe fn get_unchecked(&mut self, _idx: usize) -> <Self as Iterator>::Item
235 where
236 Self: TrustedRandomAccessNoCoerce,
237 {
238 unreachable!("Always specialized");
239 }
240
241 #[inline]
242 default fn fold<Acc, F>(self, init: Acc, f: F) -> Acc
243 where
244 F: FnMut(Acc, Self::Item) -> Acc,
245 {
246 SpecFold::spec_fold(self, init, f)
247 }
248}
249
250#[doc(hidden)]
251impl<A, B> ZipImpl<A, B> for Zip<A, B>
252where
253 A: TrustedRandomAccessNoCoerce + Iterator,
254 B: TrustedRandomAccessNoCoerce + Iterator,
255{
256 zip_impl_general_defaults! {}
257
258 #[inline]
259 default fn size_hint(&self) -> (usize, Option<usize>) {
260 let size = cmp::min(self.a.size(), self.b.size());
261 (size, Some(size))
262 }
263
264 #[inline]
265 unsafe fn get_unchecked(&mut self, idx: usize) -> <Self as Iterator>::Item {
266 let idx = self.index + idx;
267 unsafe { (self.a.__iterator_get_unchecked(idx), self.b.__iterator_get_unchecked(idx)) }
270 }
271
272 #[inline]
273 fn fold<Acc, F>(mut self, init: Acc, mut f: F) -> Acc
274 where
275 F: FnMut(Acc, Self::Item) -> Acc,
276 {
277 let mut accum = init;
278 let len = ZipImpl::size_hint(&self).0;
279 for i in 0..len {
280 unsafe {
284 accum = f(accum, self.get_unchecked(i));
285 }
286 }
287 accum
288 }
289}
290
291#[doc(hidden)]
292impl<A, B> ZipImpl<A, B> for Zip<A, B>
293where
294 A: TrustedRandomAccess + Iterator,
295 B: TrustedRandomAccess + Iterator,
296{
297 fn new(a: A, b: B) -> Self {
298 let len = cmp::min(a.size(), b.size());
299 Zip { a, b, index: 0, len }
300 }
301
302 #[inline]
303 fn next(&mut self) -> Option<(A::Item, B::Item)> {
304 if self.index < self.len {
305 let i = self.index;
306 self.index += 1;
309 unsafe {
311 Some((self.a.__iterator_get_unchecked(i), self.b.__iterator_get_unchecked(i)))
312 }
313 } else {
314 None
315 }
316 }
317
318 #[inline]
319 fn size_hint(&self) -> (usize, Option<usize>) {
320 let len = self.len - self.index;
321 (len, Some(len))
322 }
323
324 #[inline]
325 fn nth(&mut self, n: usize) -> Option<Self::Item> {
326 let delta = cmp::min(n, self.len - self.index);
327 let end = self.index + delta;
328 while self.index < end {
329 let i = self.index;
330 self.index += 1;
333 if A::MAY_HAVE_SIDE_EFFECT {
334 unsafe {
338 self.a.__iterator_get_unchecked(i);
339 }
340 }
341 if B::MAY_HAVE_SIDE_EFFECT {
342 unsafe {
344 self.b.__iterator_get_unchecked(i);
345 }
346 }
347 }
348
349 self.super_nth(n - delta)
350 }
351
352 #[inline]
353 fn next_back(&mut self) -> Option<(A::Item, B::Item)>
354 where
355 A: DoubleEndedIterator + ExactSizeIterator,
356 B: DoubleEndedIterator + ExactSizeIterator,
357 {
358 if self.index < self.len {
362 let old_len = self.len;
363
364 self.len -= 1;
369
370 if A::MAY_HAVE_SIDE_EFFECT || B::MAY_HAVE_SIDE_EFFECT {
372 let sz_a = self.a.size();
376 let sz_b = self.b.size();
377 if sz_a != sz_b && (old_len == sz_a || old_len == sz_b) {
381 if A::MAY_HAVE_SIDE_EFFECT && sz_a > old_len {
382 for _ in 0..sz_a - old_len {
383 self.a.next_back();
384 }
385 }
386 if B::MAY_HAVE_SIDE_EFFECT && sz_b > old_len {
387 for _ in 0..sz_b - old_len {
388 self.b.next_back();
389 }
390 }
391 debug_assert_eq!(self.a.size(), self.b.size());
392 }
393 }
394 let i = self.len;
395 unsafe {
398 Some((self.a.__iterator_get_unchecked(i), self.b.__iterator_get_unchecked(i)))
399 }
400 } else {
401 None
402 }
403 }
404}
405
406#[stable(feature = "rust1", since = "1.0.0")]
407impl<A, B> ExactSizeIterator for Zip<A, B>
408where
409 A: ExactSizeIterator,
410 B: ExactSizeIterator,
411{
412}
413
414#[doc(hidden)]
415#[unstable(feature = "trusted_random_access", issue = "none")]
416unsafe impl<A, B> TrustedRandomAccess for Zip<A, B>
417where
418 A: TrustedRandomAccess,
419 B: TrustedRandomAccess,
420{
421}
422
423#[doc(hidden)]
424#[unstable(feature = "trusted_random_access", issue = "none")]
425unsafe impl<A, B> TrustedRandomAccessNoCoerce for Zip<A, B>
426where
427 A: TrustedRandomAccessNoCoerce,
428 B: TrustedRandomAccessNoCoerce,
429{
430 const MAY_HAVE_SIDE_EFFECT: bool = A::MAY_HAVE_SIDE_EFFECT || B::MAY_HAVE_SIDE_EFFECT;
431}
432
433#[stable(feature = "fused", since = "1.26.0")]
434impl<A, B> FusedIterator for Zip<A, B>
435where
436 A: FusedIterator,
437 B: FusedIterator,
438{
439}
440
441#[unstable(issue = "none", feature = "trusted_fused")]
442unsafe impl<A, B> TrustedFused for Zip<A, B>
443where
444 A: TrustedFused,
445 B: TrustedFused,
446{
447}
448
449#[unstable(feature = "trusted_len", issue = "37572")]
450unsafe impl<A, B> TrustedLen for Zip<A, B>
451where
452 A: TrustedLen,
453 B: TrustedLen,
454{
455}
456
457#[unstable(issue = "none", feature = "inplace_iteration")]
460unsafe impl<A, B> SourceIter for Zip<A, B>
461where
462 A: SourceIter,
463{
464 type Source = A::Source;
465
466 #[inline]
467 unsafe fn as_inner(&mut self) -> &mut A::Source {
468 unsafe { SourceIter::as_inner(&mut self.a) }
470 }
471}
472
473#[unstable(issue = "none", feature = "inplace_iteration")]
475unsafe impl<A: InPlaceIterable, B> InPlaceIterable for Zip<A, B> {
476 const EXPAND_BY: Option<NonZero<usize>> = A::EXPAND_BY;
477 const MERGE_BY: Option<NonZero<usize>> = A::MERGE_BY;
478}
479
480#[stable(feature = "rust1", since = "1.0.0")]
481impl<A: Debug, B: Debug> Debug for Zip<A, B> {
482 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
483 ZipFmt::fmt(self, f)
484 }
485}
486
487trait ZipFmt<A, B> {
488 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result;
489}
490
491impl<A: Debug, B: Debug> ZipFmt<A, B> for Zip<A, B> {
492 default fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
493 f.debug_struct("Zip").field("a", &self.a).field("b", &self.b).finish()
494 }
495}
496
497impl<A: Debug + TrustedRandomAccessNoCoerce, B: Debug + TrustedRandomAccessNoCoerce> ZipFmt<A, B>
498 for Zip<A, B>
499{
500 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
501 f.debug_struct("Zip").finish()
504 }
505}
506
507#[doc(hidden)]
561#[unstable(feature = "trusted_random_access", issue = "none")]
562#[rustc_specialization_trait]
563pub unsafe trait TrustedRandomAccess: TrustedRandomAccessNoCoerce {}
564
565#[doc(hidden)]
574#[unstable(feature = "trusted_random_access", issue = "none")]
575#[rustc_specialization_trait]
576pub unsafe trait TrustedRandomAccessNoCoerce: Sized {
577 fn size(&self) -> usize
579 where
580 Self: Iterator,
581 {
582 self.size_hint().0
583 }
584 const MAY_HAVE_SIDE_EFFECT: bool;
587}
588
589#[doc(hidden)]
596#[inline]
597pub(in crate::iter::adapters) unsafe fn try_get_unchecked<I>(it: &mut I, idx: usize) -> I::Item
598where
599 I: Iterator,
600{
601 unsafe { it.try_get_unchecked(idx) }
604}
605
606unsafe trait SpecTrustedRandomAccess: Iterator {
607 unsafe fn try_get_unchecked(&mut self, index: usize) -> Self::Item;
610}
611
612unsafe impl<I: Iterator> SpecTrustedRandomAccess for I {
613 default unsafe fn try_get_unchecked(&mut self, _: usize) -> Self::Item {
614 panic!("Should only be called on TrustedRandomAccess iterators");
615 }
616}
617
618unsafe impl<I: Iterator + TrustedRandomAccessNoCoerce> SpecTrustedRandomAccess for I {
619 #[inline]
620 unsafe fn try_get_unchecked(&mut self, index: usize) -> Self::Item {
621 unsafe { self.__iterator_get_unchecked(index) }
624 }
625}
626
627trait SpecFold: Iterator {
628 fn spec_fold<B, F>(self, init: B, f: F) -> B
629 where
630 Self: Sized,
631 F: FnMut(B, Self::Item) -> B;
632}
633
634impl<A: Iterator, B: Iterator> SpecFold for Zip<A, B> {
635 #[inline]
637 default fn spec_fold<Acc, F>(mut self, init: Acc, mut f: F) -> Acc
638 where
639 F: FnMut(Acc, Self::Item) -> Acc,
640 {
641 let mut accum = init;
642 while let Some(x) = ZipImpl::next(&mut self) {
643 accum = f(accum, x);
644 }
645 accum
646 }
647}
648
649impl<A: TrustedLen, B: TrustedLen> SpecFold for Zip<A, B> {
650 #[inline]
651 fn spec_fold<Acc, F>(mut self, init: Acc, mut f: F) -> Acc
652 where
653 F: FnMut(Acc, Self::Item) -> Acc,
654 {
655 let mut accum = init;
656 loop {
657 let (upper, more) = if let Some(upper) = ZipImpl::size_hint(&self).1 {
658 (upper, false)
659 } else {
660 (usize::MAX, true)
662 };
663
664 for _ in 0..upper {
665 let pair =
666 unsafe { (self.a.next().unwrap_unchecked(), self.b.next().unwrap_unchecked()) };
669 accum = f(accum, pair);
670 }
671
672 if !more {
673 break;
674 }
675 }
676 accum
677 }
678}